package com.ctyun.xstore.vod;

import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import com.alibaba.fastjson.JSON;
import com.ctyun.xstore.vod.auth.SignParam;
import com.ctyun.xstore.vod.auth.Signature;
import com.ctyun.xstore.vod.exception.ServerErrorException;
import com.ctyun.xstore.vod.internal.AESCipherUtils;
import com.ctyun.xstore.vod.internal.FastJsonConfig;
import com.ctyun.xstore.vod.internal.HttpRequestQuery;
import com.ctyun.xstore.vod.internal.HttpStatus;
import com.ctyun.xstore.vod.internal.OkHttpClientBuilder;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Request.Builder;
import okhttp3.RequestBody;
import okhttp3.Response;

public abstract class AbstractVODClient {

	private static final String DEFAULT_HOST = "https://vod-api.xstore.ctyun.cn/xstore-vod";

	private static final MediaType MEDIA_TYPE_JSON = MediaType.get("application/json; charset=utf-8");

	private final String host;

	private final String accessKey;

	private final String secretKey;

	private final OkHttpClient httpClient = OkHttpClientBuilder.singaletonClient();

	public AbstractVODClient(String accessKey, String secretKey) {
		this(DEFAULT_HOST, accessKey, secretKey);
	}

	public AbstractVODClient(String host, String accessKey, String secretKey) {
		super();
		this.host = this.formatHost(host);
		this.accessKey = accessKey;
		this.secretKey = secretKey;
	}

	private String formatHost(String host) {
		String h = host;
		while (h.endsWith("/")) {
			h = h.substring(0, h.length() - 1);
		}
		return h;
	}

	/**
	 * 执行一项请求，返回相关的结果。
	 *
	 * @param <T>
	 *            一个继承 AbstractTranscodeBizResponse 的类
	 * @param request
	 *            一个继承 AbstractTranscodeBizRequest 的请求类
	 * @param clz
	 *            一个继承 AbstractTranscodeBiz Request 的响应类
	 * @return clz 参数的实例。
	 * @throws IOException
	 *             可能会抛出 IO 异常
	 */
	public <T extends AbstractVODResponse<?>> T execute(AbstractVODRequest request, Class<T> clz) throws IOException {
		URL url = new URL(this.host + request.getPath());
		HttpRequestQuery query = new HttpRequestQuery(url.getQuery());
		String zoneDateTime = Signature.getZoneDateTime();

		SignParam signParam = new SignParam.Builder().setHttpMethod("POST").setAccessKey(this.accessKey)
				.setSecretKey(this.secretKey).setUri(url.getPath()).setZoneDateTime(zoneDateTime)
				.setHeaders(request.getHeaders()).setParameterNames(query.getParameterMap().keySet()).build();
		String sign = Signature.sign(signParam);

		String json = JSON.toJSONString(request, FastJsonConfig.getSerializeConfig());

		Builder requestBuilder = new Request.Builder().url(url);
		request.getHeaders().entrySet().stream().forEach(
				entry -> entry.getValue().stream().forEach(val -> requestBuilder.addHeader(entry.getKey(), val)));

		RequestBody body;
		if (request.isEncrypt()) {
			requestBuilder.addHeader("encrypt", "true");
			body = RequestBody.create(
					AESCipherUtils.encrypt(json.getBytes(StandardCharsets.UTF_8), request.getCipherPass()),
					MEDIA_TYPE_JSON);
		} else {
			body = RequestBody.create(json, MEDIA_TYPE_JSON);
		}

		Request req = requestBuilder.addHeader("Date", zoneDateTime).addHeader("signature", sign).post(body).build();

		try (Response res = httpClient.newCall(req).execute()) {
			String resBodyStr = res.body().string();
			if (res.isSuccessful()) {
				try {
					return JSON.parseObject(resBodyStr, clz, FastJsonConfig.getParseConfig());
				} catch (Exception e) {
					throw new ServerErrorException(HttpStatus.CODE_500, "VOD返回错误信息为：%s", resBodyStr);
				}
			}
			throw new ServerErrorException(res.code(), resBodyStr);
		}
	}

}
